import Game

#Spaces on the board come in pairs
#Each is marked [flag number]_[player number]
board = Game.Board('1_1','2_1','3_1','4_1','5_1','6_1','7_1','8_1','9_1',
                   '1_2','2_2','3_2','4_2','5_2','6_2','7_2','8_2','9_2')

class BLCard(Game.Card):
    def __init__(self,suit,val): self.suit,self.rank,self.value = suit,str(val),val
    def __str__(self): return self.suit + " " + self.rank
    def shortStr(self): return str(self.suit[0]) + self.rank

deck = Game.Deck()
#Create the set of BLCards that will be the cards in the deck
#Put them into the deck as they are created
for x in range(10):
    deck.addCard(BLCard("Red",x+1))
    deck.addCard(BLCard("Blue",x+1))
    deck.addCard(BLCard("Green",x+1))
    deck.addCard(BLCard("Orange",x+1))
    deck.addCard(BLCard("Purple",x+1))
    deck.addCard(BLCard("Yellow",x+1))
#Shuffle
deck.shuffle()

player1,player2 = players = Game.initPlayers(2,board,('hand','claimed flags'),())
for p in players:
    p.addItems(deck.draw(7))
player1.setName("Player 1")
player2.setName("Player 2")

#The list of unclaimed flags
unclaimedFlags = range(10)[1:]

#Evaluate a given position
def eval(position):
    #maxSum is the maximum sum of card values
    maxSum = 30
    #Get the list of cards
    cards = board.contents(position)
    #Sum their values
    sum = 0
    for c in cards: sum += c.value
    #If there are fewer than three cards, the evaluation is their sum
    if len(cards) < 3: return sum
    #There are three cards
    else:
        def straight(trio): return trio[0].value == trio[1].value - 1 == trio[2].value - 2
        def flush(trio): return trio[0].suit == trio[1].suit == trio[2].suit
        def triple(trio): return trio[0].value == trio[1].value == trio[2].value
        #If the cards are a straight flush, this is the highest valued special formation
        #Bonus equal to four times the maximum sum, it will beat Hosts, Straights, Flushes, Triples, and lower Straight Flushes
        if straight(cards) and flush(cards):
            return sum + 4*maxSum
        #If the cards are three of a kind, this is the second highest valued special formation
        #Bonus equal to thrice the maximum sum, it will beat Hosts, Straights, Flushes, and lower triples
        elif triple(cards):
            return sum + 3*maxSum
        #If the cards are a flush, this is the second lowest valued special formation
        #Bonus equal to twice the maximum sum, it will beat Hosts, Straights, and lower flushes
        elif flush(cards):
            return sum + 2*maxSum
        #If the cards are in a straight, this is the lowest valued special formation
        #Bonus equal to the maximum sum, it will beat Hosts and lower straights
        elif straight(cards):
            return sum + maxSum
        #Otherwise, it is a three card Host
        else: return sum

#Evaluate a position on the Board
def evaluate(position):
    #Get the values for each player
    p1Val = eval(position + '_1')
    p2Val = eval(position + '_2')
    
    #If one is greater than the other, return the appropriate player, otherwise return None
    if p1Val > p2Val: return player1
    elif p1Val < p2Val: return player2
    else: return None

#Print out the board
def printBoard():
    #Build a string out of a cardlist
    def buildString(cardlist):
        #Start with None (this makes convenient output)
        out = None
        #Iterate over the cards in the list, the first one is the base string, the rest are appended
        for x in cardlist:
            if x == cardlist[0]: out = x.shortStr()
            else: out += ", " + x.shortStr()
        #Return the produced string
        return out
    
    print("-----BOARD-----")
    print("Player 1's flags: " + str(player1.getContents('claimed flags')))
    print("Player 2's flags: " + str(player2.getContents('claimed flags')))
    #Iterate over the flags on the board
    for x in range(10)[1:]:
        #Build strings for each player
        p1Cards = buildString(board.contents(str(x) + '_1'))
        p2Cards = buildString(board.contents(str(x) + '_2'))
        #Print out the board
        print("FLAG " + str(x))
        print("Player 1: " + str(p1Cards))
        print("Player 2: " + str(p2Cards))

#A single player's turn
def turn(Player):
    global unclaimedFlags
    p1 = Player == player1
    
    printBoard()
    
    #Wait for confirmation
    while Player.select(str(Player) + "'s turn.",["Okay"]) != "Okay": pass
    
    #Select a card from hand
    card = None
    while card == None: card = Player.select(str(Player) + ", select a card.",Player.getContents('hand'))
    
    #Select an unclaimed flag to play on, 1-9
    flag = None
    while flag == None or flag not in unclaimedFlags: flag = Player.select("Select a flag to play on.",unclaimedFlags)
    loc = str(flag)
    oppLoc = str(flag)
    #Append the suffixes appropriate to the player playing
    if p1:
        loc += '_1'
        oppLoc += '_2'
    else:
        loc += '_2'
        oppLoc += '_1'
    
    #Play the card
    Player.play(card,loc,'hand')
    
    #If the flag has been filled
    if len(board.contents(loc)) == 3 and len(board.contents(oppLoc)) == 3:
        #Find the victor
        victor = evaluate(str(flag))
        #Remove the flag from the unclaimed flags, since it must be claimed or a draw
        unclaimedFlags.remove(flag)
        #If it is not a draw, award the flag
        if victor != None: victor.add(int(loc[0]),'claimed flags')
    
    #Claim flags
    claim = 1
    #While the claimer does not choose to exit
    while claim != None:
        claim = Player.select("Pick a flag to claim, if any.",unclaimedFlags)
        #If a flag has been claimed
        if claim != None:
            #Get the other player's response to that claim
            other = player1
            if p1: other = player2
            response = other.select(str(other) + ", do you accept " + str(Player) + "'s claim to flag " + str(claim) + "?",["Yes","No"])
            #If the player accepts the claim, remove the flag from unclaimed flags, and add it to claimed flags
            if response == "Yes":
                unclaimedFlags.remove(claim)
                Player.add(claim,'claimed flags')
    
    #Draw a card from the deck
    Player.add(deck.draw(),'hand')

def winner():
    #Get and store the flags for each player
    p1Flags = player1.getContents('claimed flags')
    p2Flags = player2.getContents('claimed flags')
    
    #Return any player with five or more flags
    if len(p1Flags) >= 5: return player1
    if len(p2Flags) >= 5: return player2
    
    #Search each player for three consecutive flags, since this also constitutes a win
    for x in range(7):
        if x+1 in p1Flags and x + 2 in p1Flags and x + 3 in p1Flags:
            return player1
        if x+1 in p2Flags and x + 2 in p2Flags and x + 3 in p2Flags:
            return player2
    return None

end = False
result = None
while not end:
    for p in players:
        result = winner()
        if result != None:
            end = True
        else:
            turn(p)